 /* ____  _____             ____    ____    _                                 ______    _________   ____  _    *
 * |_   \|_   _|           |_   \  /   _|  (_)                              .' ____ \  |  _   _  | |_   _|     *
 *   |   \ | |    __   _     |   \/   |    __    .---.   _ .--.    .--.     | (___ \_| |_/ | | \_|   | |       *
 *   | |\ \| |   [  | | |    | |\  /| |   [  |  / /'`\] [ `/'`\] / .'`\ \    _.____`.      | |       | |   _   *
 *  _| |_\   |_   | \_/ |,  _| |_\/_| |_   | |  | \__.   | |     | \__. |   | \____) |    _| |_     _| |__/ |  *
 * |_____|\____|  '.__.'_/ |_____||_____| [___] '.___.' [___]     '.__.'     \______.'   |_____|   |________|  *
 *                                                                                                             *
 * @file     main.c																							   *
 * @version  V3.00																							   *
 * $Revision: 6 $
 * $Date: 21/03/11 6:57p $
 * @brief    Show the usage of clock fail detector and clock frequency monitor function.
 * @note                                                                                                       *
 * SPDX-License-Identifier: Apache-2.0                                                                         *
 * @copyright (C) 2016-2020 Nuvoton Technology Corp. All rights reserved.                                      *
 ***************************************************************************************************************/
#include "stdio.h"
#include "nuc980.h"
#include "gpio.h"
#include "IEC60730_CONTROL_PARAM.h"
#include "IEC60730_SAFETY_TEST_LIB.h"
#include "user_config.h"

extern volatile uint32_t u32TimerXCnt, u32TimerYCnt;

#ifdef __ARMCC_VERSION
extern uint32_t Image$$RW_IRAM1$$Base;
#endif

#ifdef __ICCARM__
extern uint32_t RW_IRAM1$$Base;
#endif

uint8_t volatile u8CPUTestPass=TEST_FAIL;
uint8_t volatile u8WDTTestPass;
uint8_t volatile u8PCTestPass;
uint8_t volatile u8IntTestPass;
uint8_t volatile u8StackTestPass;
uint8_t volatile u8WDTTestPass;
uint8_t volatile u8RAMTestPass=TEST_FAIL;
uint8_t volatile u8DRAMTestPass=TEST_FAIL;
uint8_t volatile u8ROMTestPass;
uint32_t volatile u32RAMStartAddr;
uint32_t volatile u32RAMEndAddr;
uint32_t volatile u32DRAMStartAddr;
uint32_t volatile u32DRAMEndAddr;

void UART0_Init(void);
void SYS_Init(void);
void InitTimerXY(void);
uint32_t InitWdt(void);
//volatile uint32_t u32Timer5Cnt;
volatile uint32_t u32TimerXCnt, u32TimerYCnt;

void ClassB_UserErrorHandling(uint8_t error_code)
{
    printf("Error Handling\n");
}

void ClassB_WatchDogReset(void)
{
    SYS_UnlockReg();
    /* reset wdt counter and time out flag */
    WDT_RESET_COUNTER();
    WDT_CLEAR_TIMEOUT_INT_FLAG();
    SYS_LockReg();
}

/*---------------------------------------------------------------------------------------------------------*/
/*  Main Function                                                                                          */
/*---------------------------------------------------------------------------------------------------------*/
int32_t main(void)
{
#if 0
    /* Init System, peripheral clock and multi-function I/O */
    SYS_Init();

    /* Init UART0 for printf */
    UART0_Init();

    printf("\n\n");

    /* ClassB Test Lib Init */
    CLASSB_TESTLIB_INIT(ClassB_UserErrorHandling, ClassB_WatchDogReset);

    if(CLASSB_STARTUP_TESTS() != 1)
        printf("start up test - [FAIL]\n");
    else
        printf("start up test - [OK]\n");

    while (1){
        /* Run Time Execution Check */
        CLASSB_CHECK_RUNTIME_TESTS_EXECUTION();
        /* Run Time Test mainloop */
        CLASSB_RUNTIME_TESTS();
    }
#else
    task_main();
#endif
}

void SYS_Init(void)
{
	/* cache settings */
    sysDisableCache();
    sysFlushCache(I_D_CACHE);
    sysEnableCache(CACHE_WRITE_BACK);

    /* Enable perpherial module clock */
	/* Enable WDT engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | BIT0);
	/* Enable WWDT engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | BIT1);
    /* Enable ETIMER0 engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | BIT8);
    /* Enable UART0 clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | BIT16);

    /* Init WDT */
	InitWdt();

    /* Init TimerX */
	InitTimerXY();
}

void UART0_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init UART                                                                                               */
    /*---------------------------------------------------------------------------------------------------------*/
    /* GPF11, GPF12 */
    outpw(REG_SYS_GPF_MFPH, (inpw(REG_SYS_GPF_MFPH) & 0xfff00fff) | 0x11000);   // UART0 multi-function

    /* UART0 line configuration for (115200,n,8,1) */
    outpw(REG_UART0_LCR, inpw(REG_UART0_LCR) | 0x07);
    outpw(REG_UART0_BAUD, 0x30000066); /* 12MHz reference clock input, 115200 */
}

/*-------------------------------------------*/
/*                wdt isr                    */
/*-------------------------------------------*/
void WDT_IRQHandler()
{
    /* for wdt startup test */
    SYS_UnlockReg();
    WDT_RESET_COUNTER();
    WDT_CLEAR_TIMEOUT_INT_FLAG();
//    u32WdtInt = TRUE;
//    SYS_LockReg();
}

/*-------------------------------------------*/
/*                timerX isr                 */
/*-------------------------------------------*/
void ETMRX_IRQHandler(void)
{
    /* clear timerX interrupt flag */
    ETIMER_ClearIntFlag(TIMERX);

    /* call CLASSB_HSCLOCK_INIT() */
    CLASSB_HSCLOCK_INT();

    u32TimerXCnt++;
}

/*-------------------------------------------*/
/*                timerY isr                 */
/*-------------------------------------------*/
void ETMRY_IRQHandler(void)
{
    /* clear timerY interrupt flag */
    ETIMER_ClearIntFlag(TIMERY);

    /* call CLASSB_LSCLOCK_INIT() */
	CLASSB_LSCLOCK_INT();

    /* increase timer count */
    u32TimerYCnt++;
}

/*-------------------------------------------*/
/*            init timerXY                   */
/*-------------------------------------------*/
void InitTimerXY(void)
{
	/*================================*/
    /*        init timerX             */
	/*================================*/
    /* select timerX clock from clk_in (12 MHz) */
    outpw(REG_CLK_DIVCTL8, inpw(REG_CLK_DIVCTL8) & ~(0x3<<(16+TIMERX*2)));

    /* enable ETIMERX engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << (8+TIMERX)));

    /* set timerX frequency (Hz) */
    ETIMER_Open(TIMERX, ETIMER_PERIODIC_MODE, TIMERX_RUNTIME_FREQ);
    u32TimerXCnt = 0;

    /* setup timerX interrupt */
    ETIMER_ClearIntFlag(TIMERX);
    sysInstallISR(IRQ_LEVEL_1, IRQ_TIMERX, (PVOID)ETMRX_IRQHandler);
    ETIMER_EnableInt(TIMERX);
    sysEnableInterrupt(IRQ_TIMERX);

	/*================================*/
    /*        init timerY             */
	/*================================*/
#ifdef TIMERY_RUNTIME_FROM_32K
    /* enable 32K clock input */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | BIT2);
    RTC->INIT = RTC_INIT_KEY;
    while(!((RTC->INIT) & 0x01));
    RTC_WaitAccessEnable();
    outpw(REG_RTC_CLKCTL, inpw(REG_RTC_CLKCTL) | BIT0);
    RTC_Check();

    /* select timerY clock from 32k */
    outpw(REG_CLK_DIVCTL8, inpw(REG_CLK_DIVCTL8) | (0x3<<(16+TIMERY*2)));
#else
    /* select timerY clock from PCLK */
    outpw(REG_CLK_DIVCTL8, (inpw(REG_CLK_DIVCTL8)
                            & ~(0x3<<(16+TIMERY*2))) | (0x1<<(16+TIMERY*2)));
#endif
    /* enable ETIMERY engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | (1 << (8+TIMERY)));

    /* set timerY frequency (Hz) */
    ETIMER_Open(TIMERY, ETIMER_PERIODIC_MODE, TIMERY_RUNTIME_FREQ);
    u32TimerYCnt = 0;

    /* setup timerY interrupt */
    ETIMER_ClearIntFlag(TIMERY);
    sysInstallISR(IRQ_LEVEL_1, IRQ_TIMERY, (PVOID)ETMRY_IRQHandler);
    ETIMER_EnableInt(TIMERY);
    sysEnableInterrupt(IRQ_TIMERY);

	/*================================*/
    /*    start timerX and timerXY    */
	/*================================*/
    /* enable global interrupt */
    sysSetLocalInterrupt(ENABLE_IRQ);

    /* start timer0 and timer5 */
    ETIMER_Start(TIMERX);
    ETIMER_Start(TIMERY);
}

/*-------------------------------------------*/
/*                init WDT                   */
/*-------------------------------------------*/
uint32_t InitWdt(void)
{
    /* unlock register */
    SYS_UnlockReg();

    /* select WDT clock source from clk_in/512 (12 MHz/512) */
    outpw(REG_CLK_DIVCTL8, (inpw(REG_CLK_DIVCTL8) & ~0x300) | 0x100);

    /* enable WDT engine clock */
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | 1);

    /* Configure WDT settings and start WDT counting, Set WDT time out interval
       to 2^14 Twdt = 0.7 sec. Where Twdt = 12MHZ / 512 */
    WDT_Open(WDT_TIMEOUT_2POW14, WDT_RESET_DELAY_18CLK, TRUE, TRUE);

    /* init flag */
//    u32WdtInt = FALSE;

    /* enable WDT interrupt function */
    WDT_EnableInt();

    return TRUE;
}
